﻿namespace FastColoredTextBoxNS
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Windows.Forms;

    public partial class HotkeysEditorForm : Form
    {
        private readonly BindingList<HotkeyWrapper> wrappers = new BindingList<HotkeyWrapper>();

        public HotkeysEditorForm(HotkeysMapping hotkeys)
        {
            this.InitializeComponent();
            this.BuildWrappers(hotkeys);
            this.dgv.DataSource = this.wrappers;
        }

        private int CompereKeys(Keys key1, Keys key2)
        {
            int res = ((int)key1 & 0xff).CompareTo((int)key2 & 0xff);
            if (res == 0)
            {
                res = key1.CompareTo(key2);
            }

            return res;
        }

        private void BuildWrappers(HotkeysMapping hotkeys)
        {
            var keys = new List<Keys>(hotkeys.Keys);
            keys.Sort(this.CompereKeys);

            this.wrappers.Clear();
            foreach (var k in keys)
            {
                this.wrappers.Add(new HotkeyWrapper(k, hotkeys[k]));
            }
        }

        /// <summary>
        /// 	Returns edited hotkey map
        /// </summary>
        /// <returns> </returns>
        public HotkeysMapping GetHotkeys()
        {
            var result = new HotkeysMapping();
            foreach (var w in this.wrappers)
            {
                result[w.ToKeyData()] = w.Action;
            }

            return result;
        }

        private void btAdd_Click(object sender, EventArgs e)
        {
            this.wrappers.Add(new HotkeyWrapper(Keys.None, FCTBAction.None));
        }

        private void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            var cell = (this.dgv[0, e.RowIndex] as DataGridViewComboBoxCell);
            if (cell.Items.Count == 0)
            {
                foreach (
                    var item in
                        new[]
                            {
                                "", "Ctrl", "Ctrl + Shift", "Ctrl + Alt", "Shift", "Shift + Alt", "Alt",
                                "Ctrl + Shift + Alt"
                            })
                {
                    cell.Items.Add(item);
                }
            }

            cell = (this.dgv[1, e.RowIndex] as DataGridViewComboBoxCell);
            if (cell.Items.Count == 0)
            {
                foreach (var item in Enum.GetValues(typeof(Keys)))
                {
                    cell.Items.Add(item);
                }
            }

            cell = (this.dgv[2, e.RowIndex] as DataGridViewComboBoxCell);
            if (cell.Items.Count == 0)
            {
                foreach (var item in Enum.GetValues(typeof(FCTBAction)))
                {
                    cell.Items.Add(item);
                }
            }
        }

        private void btResore_Click(object sender, EventArgs e)
        {
            var h = new HotkeysMapping();
            h.InitDefault();
            this.BuildWrappers(h);
        }

        private void btRemove_Click(object sender, EventArgs e)
        {
            for (int i = this.dgv.RowCount - 1; i >= 0; i--)
            {
                if (this.dgv.Rows[i].Selected)
                {
                    this.dgv.Rows.RemoveAt(i);
                }
            }
        }

        private void HotkeysEditorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                string actions = this.GetUnAssignedActions();
                if (!string.IsNullOrEmpty(actions))
                {
                    if (
                        MessageBox.Show(
                            "Some actions are not assigned!\r\nActions: " + actions
                            + "\r\nPress Yes to save and exit, press No to continue editing",
                            "Some actions is not assigned",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
                    {
                        e.Cancel = true;
                    }
                }
            }
        }

        private string GetUnAssignedActions()
        {
            var sb = new StringBuilder();
            var dic = new Dictionary<FCTBAction, FCTBAction>();

            foreach (var w in this.wrappers)
            {
                dic[w.Action] = w.Action;
            }

            foreach (var item in Enum.GetValues(typeof(FCTBAction)))
            {
                if ((FCTBAction)item != FCTBAction.None)
                {
                    if (!((FCTBAction)item).ToString().StartsWith("CustomAction"))
                    {
                        if (!dic.ContainsKey((FCTBAction)item))
                        {
                            sb.Append(item + ", ");
                        }
                    }
                }
            }

            return sb.ToString().TrimEnd(' ', ',');
        }
    }

    internal class HotkeyWrapper
    {
        public HotkeyWrapper(Keys keyData, FCTBAction action)
        {
            var a = new KeyEventArgs(keyData);
            this.Ctrl = a.Control;
            this.Shift = a.Shift;
            this.Alt = a.Alt;

            this.Key = a.KeyCode;
            this.Action = action;
        }

        public Keys ToKeyData()
        {
            Keys res = this.Key;
            if (this.Ctrl)
            {
                res |= Keys.Control;
            }
            if (this.Alt)
            {
                res |= Keys.Alt;
            }
            if (this.Shift)
            {
                res |= Keys.Shift;
            }

            return res;
        }

        private bool Ctrl;

        private bool Shift;

        private bool Alt;

        public string Modifiers
        {
            get
            {
                string res = "";
                if (this.Ctrl)
                {
                    res += "Ctrl + ";
                }
                if (this.Shift)
                {
                    res += "Shift + ";
                }
                if (this.Alt)
                {
                    res += "Alt + ";
                }

                return res.Trim(' ', '+');
            }
            set
            {
                if (value == null)
                {
                    this.Ctrl = this.Alt = this.Shift = false;
                }
                else
                {
                    this.Ctrl = value.Contains("Ctrl");
                    this.Shift = value.Contains("Shift");
                    this.Alt = value.Contains("Alt");
                }
            }
        }

        public Keys Key { get; set; }

        public FCTBAction Action { get; set; }
    }
}